package com.factory.server.dao;

import com.factory.server.bo.AbstractBusinessObject;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

/**
 * Implementace DAO dispatcheru
 * Posle genericke pozadavky na specificke DAO, je-li zaregistrovano pro danou tridu (entitu)
 * neni-li takove DAO registrovano, posle pozadavek generickemu DAO objektu.
 *
 * Timto se zajisti snadne pridani specificke funkcionality, nebyla-li drive zapotrebi
 * a byly-li k tomuto ucelu pouzivany genericke volani.
 *
 * @author Pavel Micka (mickapa1@fel.cvut.cz)
 */
@Component("daoDispatcher")
public class GenericDAODispatcher implements DAODispatcherIface {

    private Map<Class, SpecificDAOIface> registry;
    @Autowired
    @Qualifier("jpaDao")
    private GenericDAOIface genericDAO;

    public GenericDAODispatcher() {
        this.registry = new HashMap<Class, SpecificDAOIface>();
    }

    public <ENTITY> List<ENTITY> getAll(Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return registry.get(clazz).getAll();
        } else {
            return genericDAO.getAll(clazz);
        }
    }

    public <ENTITY extends AbstractBusinessObject> void removeById(long id, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            registry.get(clazz).removeById(id);
        } else {
            genericDAO.removeById(id, clazz);
        }
    }

    public <ENTITY extends AbstractBusinessObject> void remove(ENTITY o) {
        if (registry.containsKey(o.getClass())) {
            registry.get(o.getClass()).remove(o);
        } else {
            genericDAO.remove(o);
        }
    }

    public <ENTITY extends AbstractBusinessObject> ENTITY saveOrUpdate(ENTITY o) {
        ENTITY e = null;
        if (registry.containsKey(o.getClass())) {
            e = (ENTITY) registry.get(o.getClass()).saveOrUpdate(o);
        } else {
            e = genericDAO.saveOrUpdate(o);
        }
        return e;
    }

    public <ENTITY> ENTITY getById(Long id, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (ENTITY) registry.get(clazz).getById(id);
        } else {
            return genericDAO.getById(id, clazz);
        }
    }

    public <ENTITY> ENTITY loadById(long id, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (ENTITY) registry.get(clazz).loadById(id);
        } else {
            return genericDAO.loadById(id, clazz);
        }
    }

    public <ENTITY> List<ENTITY> getAllOrderedDesc(String property, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (List<ENTITY>) registry.get(clazz).getAllOrderedDesc(property);
        } else {
            return genericDAO.getAllOrderedDesc(property, clazz);
        }
    }

    public <ENTITY> List<ENTITY> getAllOrderedAsc(String property, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (List<ENTITY>) registry.get(clazz).getAllOrderedAsc(property);
        } else {
            return genericDAO.getAllOrderedAsc(property, clazz);
        }
    }

    public <ENTITY> List<ENTITY> getByProperty(String property, Object value, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (List<ENTITY>) registry.get(clazz).getByProperty(property, value);
        } else {
            return genericDAO.getByProperty(property, value, clazz);
        }
    }

    public <ENTITY> ENTITY getByPropertyUnique(String property, Object value, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return (ENTITY) registry.get(clazz).getByPropertyUnique(property, value);
        } else {
            return genericDAO.getByPropertyUnique(property, value, clazz);
        }
    }

    public Long getCount(Class clazz) {
        if (registry.containsKey(clazz)) {
            return registry.get(clazz).getCount();
        } else {
            return genericDAO.getCount(clazz);
        }
    }

    public <ENTITY> List<ENTITY> getPage(int from, int maxResults, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return registry.get(clazz).getPage(from, maxResults);
        } else {
            return genericDAO.getPage(from, maxResults, clazz);
        }
    }

    public <ENTITY> List<ENTITY> getPage(int first, int rows, String sortBy, boolean ascending, Class<ENTITY> clazz) {
        if (registry.containsKey(clazz)) {
            return registry.get(clazz).getPage(first, rows, sortBy, ascending);
        } else {
            return genericDAO.getPage(first, rows, sortBy, ascending, clazz);
        }
    }

    public <ENTITY extends AbstractBusinessObject> void register(SpecificDAOIface<ENTITY> specificDAO, Class<ENTITY> clazz) {
        registry.put(clazz, specificDAO);
    }

    public <ENTITY extends AbstractBusinessObject> void unregister(Class<ENTITY> clazz) {
        registry.remove(clazz);
    }

    public <ENTITY> List<ENTITY> getByPropertyOrderedAsc(String getProperty, Object value, String sortProperty, Class<ENTITY> clazz) {
        return genericDAO.getByPropertyOrderedAsc(getProperty, value, sortProperty, clazz);
    }

    public <ENTITY> Object getMaximumValue(Class<ENTITY> clazz) {
        return genericDAO.getMaximumValue(clazz);
    }

    public <ENTITY> Object getAllProperties(String property, Class<ENTITY> clazz) {
            return genericDAO.getAllProperties(property, clazz);
    }
    
    public <ENTITY> Boolean contains(String property, Object value, Class<ENTITY> clazz){
        return genericDAO.contains(property, value, clazz);
    }
}
